﻿using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Spider.Framework.UtilityCommon.Extensions;
using MyCrawler.Entity;
using MyCrawler.Utilyties;

namespace MyCrawler.Controls
{
    public class WebTreThoCtr : ForumsCtr
    {
        /// <summary>
        /// Source code: vBulletin 4.2.1
        /// </summary>
        public WebTreThoCtr()
        {
            _source = "webtretho.com";
            _domain = "http://www.webtretho.com/";
            _linkInit = "http://www.webtretho.com/forum/";
            _blockId = DateTime.Now.ToString("yyyyMMddhhmmss");
            _pageLimit = -1;
        }

        /// <summary>
        /// Contructor thứ 2
        /// </summary>
        /// <param name="source">nguồn</param>
        /// <param name="linkInit">link khởi tạo</param>
        /// <param name="domain">domain gốc - có thể trùng với link khởi tạo</param>
        /// <param name="blockId">mỗi lần khởi tạo sẽ có 1 block id, chứa list các thread</param>
        public WebTreThoCtr(string source, string linkInit, string domain, string blockId)
        {
            _source = source;
            _linkInit = linkInit;
            _domain = domain; // dùng cho các trang sub trở đi, vì sẽ nối trang với domain
            _blockId = blockId;

            _pageLimit = -1;
        }

        /// <summary>
        /// Lấy các catogories
        /// </summary>
        /// <param name="link"></param>
        /// <param name="idParrent"></param>
        public override List<string> GetCatalogByLink()
        {
            try
            {
                string html = GetContentWithStream(_linkInit, -1);

                List<string> ls_L1 = UtilityCtr.GetListItem(html, @"<h3[\s]+style='width:[\s]+[\d]+px;'[\s]+class='forumtitle'>.*?<\/h3>");

                List<string> lsLinkStored = new List<string>();
                for (int i = 0; i < ls_L1.Count; i++)
                {
                    #region [catagories L1]
                    string link_L1 = UtilityCtr.GetItemFirst(ls_L1[i], @"href='.*?'").Replace("href='", "").Replace("'", "");

                    //truy cập vào link này xem có sub catagories nữa không
                    string html_L1 = GetContentWithStream(link_L1, -1);

                    List<string> ls_L2 = UtilityCtr.GetListItem(html_L1, @"(<li[\s]+id='forum[\d]+'[\s]+class='forumbit_post[\s]+L1').*?(<\/div>[\s]+<\/div>[\s]+<\/div>[\s]+<\/li>)");

                    if (ls_L2.Count > 0) // có con
                    {
                        #region [catagories L2]
                        // lấy các link của catagories con
                        for (int j = 0; j < ls_L2.Count; j++)
                        {
                            string link_L2 = UtilityCtr.GetItemFirst(ls_L2[j], @"<h2[\s]+class='forumtitle'>.*?<\/h2>");
                            link_L2 = UtilityCtr.GetItemFirst(link_L2, @"href='.*?'").Replace("href='", "").Replace("'", "");

                            // truy cập vào link này sub catagories nữa không
                            string html_L2 = GetContentWithStream(link_L2, -1); ;

                            List<string> ls_L3 = UtilityCtr.GetListItem(html_L2, @"(<li[\s]+id='forum[\d]+'[\s]+class='forumbit_post[\s]+L1').*?(<\/div>[\s]+<\/div>[\s]+<\/div>[\s]+<\/li>)");

                            if (ls_L3.Count > 0) // có con
                            {
                                // dò  lấy con thêm lần nữa
                                for (int k = 0; k < ls_L3.Count; k++)
                                {
                                    #region [catagories L3]
                                    string link_L3 = UtilityCtr.GetItemFirst(ls_L3[k], @"<h2[\s]+class='forumtitle'>.*?<\/h2>");
                                    link_L3 = UtilityCtr.GetItemFirst(link_L3, @"href='.*?'").Replace("href='", "").Replace("'", "");

                                    // cố truy cập vào link này sub catagories nữa không
                                    string html_L3 = GetContentWithStream(link_L3, -1);

                                    List<string> ls_L4 = UtilityCtr.GetListItem(html_L3, @"(<li[\s]+id='forum[\d]+'[\s]+class='forumbit_post[\s]+L1').*?(<\/div>[\s]+<\/div>[\s]+<\/div>[\s]+<\/li>)");

                                    // làm việc tới menu cấp 4 thôi
                                    for (int l = 0; l < ls_L4.Count; l++)
                                    {
                                        string link_L4 = UtilityCtr.GetItemFirst(ls_L4[l], @"<h2[\s]+class='forumtitle'>.*?<\/h2>");
                                        link_L4 = UtilityCtr.GetItemFirst(link_L4, @"href='.*?'").Replace("href='", "").Replace("'", "");

                                        lsLinkStored.Add(link_L4);
                                    }

                                    // kiểm tra có topic không!
                                    bool isThreadOfL3 = Regex.IsMatch(html_L3, @"<ul[\s]+class='lst_typPost[\s]+threads'[\s]+id='threads'>[\s]+<li[\s]+id='thread_[\d]+'");
                                    if (isThreadOfL3 == true)
                                    {
                                        lsLinkStored.Add(link_L3);
                                    }
                                    #endregion
                                }

                                // kiểm tra có topic không!
                                bool isThreadOfL2 = Regex.IsMatch(html_L2, @"<ul[\s]+class='lst_typPost[\s]+threads'[\s]+id='threads'>[\s]+<li[\s]+id='thread_[\d]+'");
                                if (isThreadOfL2 == true)
                                {
                                    lsLinkStored.Add(link_L2);
                                }
                            }
                            else
                            {
                                // không có con nữa, dưa link của catagories vào List
                                lsLinkStored.Add(link_L2);
                            }
                        }
                        #endregion

                        // kiểm tra có topic không!
                        bool isThread = Regex.IsMatch(html_L1, @"<ul[\s]+class='lst_typPost[\s]+threads'[\s]+id='threads'>[\s]+<li[\s]+id='thread_[\d]+'");

                        if (isThread == true)
                        {
                            lsLinkStored.Add(link_L1);
                        }
                    }
                    else
                    {
                        // không có con nữa, dưa link của catagories vào List
                        lsLinkStored.Add(link_L1);
                    }
                    #endregion
                }

                return lsLinkStored;
            }
            catch
            { }
            return null;
        }

        public override void GetListTopic_InCatagory(string lnkCat)
        {
            try
            {
                TraceLog_Status(_source, _blockId, " + " + lnkCat);

                string html = GetContentWithStream(lnkCat, -1);

                if (html.IsStringNullOrEmpty())
                {
                    TraceLog_Status(_source, _blockId, " --- Data null Or empty. WebClient request time out. Kiểm tra Website có bị chết hay không hay kiểm tra kết nối internet của bạn! "); // ghi log để test
                    return;
                }

                // lấy dữ liệu trang đầu
                GetListTopicInPage(html, 1); // 1 trang hiện hành là trang đầu

                #region lấy dữ liệu trang thứ 2 trở đi, nếu có
                try
                {
                    string numPage = UtilityCtr.GetItemFirst(html, @"'>Trang[\s]+[\d]+\/[\d]+<\/span>");
                    numPage = Regex.Replace(numPage, @"'>Trang[\s]+[\d]+\/", "").Replace("</span>", "");

                    int totalPage = Convert.ToInt32(numPage);

                    _pageLimit = -1; // khởi tạo trang giới hạn
                    for (int j = 2; j <= totalPage; j++) // duyêt từ trang số 2 trở đi
                    {
                        if (_pageLimit != -1 && j > _pageLimit) // đã tìm thấy trang giới hạn, trang này có ngày cập nhật nhỏ hơn ngày giới hạn
                        {
                            break;
                        }

                        string linkItem = lnkCat + "index" + j.ToString() + ".html";

                        string htmlItem = GetContentWithStream(linkItem, -1);
                        GetListTopicInPage(htmlItem, j);
                    }
                }
                catch
                { }
                #endregion
            }
            catch { }
        }

        /// <summary>
        /// lấy các topic trong 1 trang (của 1 chủ đề)
        /// </summary>
        /// <param name="html"></param>
        /// <param name="pageCurr"></param>
        private void GetListTopicInPage(string html, int pageIndex)
        {
            try
            {
                string htmlForum = UtilityCtr.GetItemFirst(html, @"<ul class='lst_typPost threads' id='threads'>.*?<p class='cl'>[\s]+<\/p>[\s]+<\/li>[\s]+<\/ul>");

                string pattLisDiv = @"<div[\s]+class='ctn_typPost'>.*?[\s]+<\/div>[\s]+<div[\s]+class='folTypPost'>";
                List<string> ls = UtilityCtr.GetListItem(htmlForum, pattLisDiv);

                if (ls == null || ls.Count == 0)
                {
                    TraceLog_Status(_source, _blockId, " --- không tìm thấy Topic, kiểm tra Catagorie này có thay đổi source code!");
                    return;
                }

                for (int i = 0; i < ls.Count; i++)
                {
                    bool isPrefix = Regex.IsMatch(ls[i], @"\?prefixid=");

                    if (isPrefix == true)
                    {
                        continue;
                    }

                    string day = UtilityCtr.GetItemFirst(ls[i], @"([\d]+\/[\d]+\/[\d]+)|('>Hôm qua<\/)|('>Hôm nay<\/)") + " " + DateTime.Now.ToString("hh:mm:ss.fff");

                    if (day.IsStringNullOrEmpty())
                    {
                        TraceLog_Status(_source, _blockId, " --- Ngày 'last reply' không tồn tại, có thể chủ đề đã bị xóa, đã di chuyển, hay website nguồn có sự thay đổi souce code!");
                        continue;
                    }

                    if (day.ToLower().Contains("hôm nay"))
                    {
                        day = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss.fff");
                    }
                    else
                    {
                        if (day.ToLower().Contains("hôm qua"))
                        {
                            day = DateTime.Now.AddDays(-1).ToString("yyyy-MM-dd hh:mm:ss.fff");
                        }
                        else
                        {
                            // // 15/04/2014 10:25:41.954 chuyển về dạng yyyy-MM-dd
                            string[] arrDate = day.Split(' ');
                            if (arrDate.Length == 2)
                            {
                                string[] arrDay = arrDate[0].Split('/');
                                day = arrDay[2] + "-" + arrDay[1] + "-" + arrDay[0] + " " + arrDate[1];
                            }
                        }
                    }

                    try
                    {
                        DateTime dtLastDate = Convert.ToDateTime(day);

                        // kiểm tra ngày này có nhỏ hơn ngày giới hạn lấy hay không?
                        if (dtLastDate >= _dtLimit)// lấy dữ liệu mới về
                        {
                            string subject = UtilityCtr.GetItemFirst(ls[i], @"<h3>.*?<\/h3>").Replace("<h3>", "").Replace("</h3>", "");
                            string link = UtilityCtr.GetItemFirst(ls[i], @"(<a[\s]+class='title.*?'[\s]+href=')(.*?)(')");
                            link = Regex.Replace(link, @"(<a[\s]+class='title.*?'[\s]+href=')|(')", "");

                            if (link.IsStringNullOrEmpty())
                            {
                                TraceLog_Status(_source, _blockId, " --- Link của topic rỗng, có thể website nguồn có sự thay đổi souce code!");
                                continue; // chạy tới topic kế mà không quan tâm đoạn dưới
                            }

                            int idTopicGet;
                            try
                            {
                                idTopicGet = Convert.ToInt32(UtilityCtr.GetItemFirst(ls[i], @"-[\d]+\/").Replace("-", "").Replace("/", ""));
                            }
                            catch
                            {
                                idTopicGet = 0;
                            }

                            ForumTopicEntity obj = new ForumTopicEntity();

                            obj.IdTopicGet = idTopicGet;
                            obj.DtPost = dtLastDate;
                            obj.DtReply = dtLastDate;
                            obj.Link = link.Trim();
                            obj.TotalReply = -1; // chưa set
                            obj.Subject = subject.Trim();
                            obj.Contents = "";
                            obj.IdCatagories = 0;
                            obj.ImgAvatar = "";
                            obj.Username = "";
                            obj.View = -1; // chưa set

                            // gọi lấy content
                            GetContentOfTopic(obj);
                        }
                        else
                        {
                            if (pageIndex > 1)
                            {
                                _pageLimit = pageIndex; // chủ đề này có thời gian post cũ hơn ngày giới hạn, thoát luôn và không quan tâm chủ đề cũ hơn nữa
                                break;
                            }
                        }
                    }
                    catch
                    { }
                }
            }
            catch (Exception ex) { }
        }

        private void GetContentOfTopic(ForumTopicEntity fr)
        {
            try
            {
                // ghi log để test
                TraceLog_Status(_source, _blockId, " --- " + fr.Link);

                string html = GetContentWithStream(fr.Link, -1);

                if (html.IsStringNullOrEmpty())
                {
                    TraceLog_Status(_source, _blockId, " --- --- Data null Or empty. WebClient request time out. Kiểm tra Website có bị chết hay không hay kiểm tra kết nối internet của bạn! "); // ghi log để test
                    return;
                }

                #region [lấy tên danh mục]

                List<string> lsCat = UtilityCtr.GetListItem(html, @"<span itemprop='title'>.*?<\/span>");
                string catName = "";
                if (lsCat == null || lsCat.Count == 0)
                {
                    TraceLog_Status(_source, _blockId, " --- --- Lấy tên danh mục trên thanh navigation rỗng, có thể website nguồn có sự thay đổi souce code!");
                }
                else
                {
                    catName = Regex.Replace(lsCat[lsCat.Count - 1], @"<.*?>", "");
                }

                #endregion

                List<string> lisBlockquote = UtilityCtr.GetListItem(html, @"<blockquote class='postcontent restore'>.*?<\/blockquote>");

                if (lisBlockquote == null || lisBlockquote.Count == 0)
                {
                    TraceLog_Status(_source, _blockId, " --- --- Bài viết và Bình luận = 0, có thể website nguồn có sự thay đổi souce code, hay ip bị block!");
                    return;
                }

                //Lấy content
                string content = Regex.Replace(lisBlockquote[0], @"<.*?>", " ");
                content = Regex.Replace(content, @"[\s]+", " ").Trim();

                #region [Lấy các bình luận tại trang đầu]
                List<string> lsCmt = new List<string>();

                for (int i = 1; i < lisBlockquote.Count; i++) // từ vị trí 1 trở đi, vì 0 là content lấy rồi
                {
                    string cmt = Regex.Replace(lisBlockquote[i], @"<.*?>", " ");
                    cmt = Regex.Replace(content, @"[\s]+", " ").Trim();

                    lsCmt.Add(cmt);
                }

                #endregion

                #region [Lấy các bình luận từ trang 2 trở đi - nếu có]
                try
                {
                    string numPage = UtilityCtr.GetItemFirst(html, @"'>Trang[\s]+[\d]+\/[\d]+<\/span>");
                    numPage = Regex.Replace(numPage, @"'>Trang[\s]+[\d]+\/", "").Replace("</span>", "");

                    int totalPage = Convert.ToInt32(numPage);

                    int start = 2;
                    if (totalPage > 200) // lớn hơn 200 trang, nhiều quá quét mãi không hết lấy thế thôi
                    {
                        start = totalPage - 200; // chỉ lấy 200 cmt mới nhất
                    }

                    for (int j = start; j <= totalPage; j++) // duyêt từ trang số 2 trở đi
                    {
                        if (_pageLimit != -1 && j > _pageLimit) // đã tìm thấy trang giới hạn, trang này có ngày cập nhật nhỏ hơn ngày giới hạn
                        {
                            break;
                        }

                        string linkItem = fr.Link + "index" + j.ToString() + ".html";
                        string htmlSub = GetContentWithStream(linkItem, -1);

                        List<string> lisBlockquoteSub = UtilityCtr.GetListItem(htmlSub, @"<blockquote class='postcontent restore'>.*?<\/blockquote>");
                        for (int k = 0; k < lisBlockquoteSub.Count; k++) // từ vị trí 1 trở đi, vì 0 là content lấy rồi
                        {
                            string cmtItem = Regex.Replace(lisBlockquoteSub[k], @"<.*?>", " ");
                            cmtItem = Regex.Replace(cmtItem, @"[\s]+", " ").Trim();

                            lsCmt.Add(cmtItem);
                        }
                    }
                }
                catch
                { }

                #endregion

                #region [save]

                ContentEntity entity = new ContentEntity();

                entity.Category = catName;
                entity.Comments = lsCmt;
                entity.Content = content;
                entity.Id = fr.IdTopicGet;
                entity.LastModify = fr.DtReply;
                entity.Link = fr.Link;
                entity.Source = _source;
                entity.Summury = "";
                entity.Title = fr.Subject;

                // ghi log để review
                TraceLog_Status(_source, _blockId, " --- --- Comments: " + lsCmt.Count.ToString() + " -- Last modify: " + fr.DtReply.ToString("yyyy-MM-dd hh:mm:ss tt"));
                // lưu vào file json
                string file = LogFileJson(entity);
                // ghi log để review
                TraceLog_Status(_source, _blockId, " --- --- File json: " + file);

                // tăng số topic lên 1 để thực hiện việc thống kê
                _totalTopic = _totalTopic + 1;
                UtilityCtr.TraceSettingTime(_source, _timeStart, _totalTopic, _dtLimit.ToString("yyyy-MM-dd hh:mm:ss tt"));
                #endregion
            }
            catch (Exception ex)
            {
                TraceLog_Status(_source, _blockId, " --- --- Error: " + ex.Message); // ghi log để test
            }
        }
    }
}
